﻿using Face8280WebSocketServer.Controllers;
using Face8280WebSocketServer.Controllers.DeviceAPI;
using Face8280WebSocketServer.DB;
using Face8280WebSocketServer.DB.User;
using Face8280WebSocketServer.Interface;
using Face8280WebSocketServer.Utility.JWT;
using Face8280WebSocketServer.Utility.Middleware;
using Face8280WebSocketServer.Utility.Model;
using Face8280WebSocketServer.WebSocket;
using Autofac;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using Ruanmou.Redis.Init;
using Ruanmou.Redis.Service;
using System.Security.Cryptography.X509Certificates;
using FaceFace8280WebSocketServer;
using FaceFace8280WebSocketServer.Option;

namespace Face8280WebSocketServer
{
    public class Startup
    {
        ILogger<Startup> _ilogger;
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            string sFile = Path.Combine(Directory.GetCurrentDirectory(), "DB", "FC8280Server.DB");
            string connecttext = $"Filename={sFile}";
            //services.AddDbContext<DbContext, FaceDBContext>(options => options.UseSqlite(connecttext));
            services.AddDbContext<DbContext, FaceDBContext>(options => options.UseSqlite(connecttext,
                (sqliteOptionsAction) =>
                {
                    //sqliteOptionsAction.MaxBatchSize(50000);

                }));

            services.AddHttpClient();
            services.AddAutoMapper(typeof(AutoMapperConfigs));
            services.AddScoped<UserDetail>();
            services.AddScoped<GlobalExceptionFilter>();
            services.Configure<PeopleOption>(Configuration.GetSection("People"));
            services.AddMvcCore(options =>
            {
                options.Filters.Add<GlobalExceptionFilter>();
            });
            //services.AddScoped<FaceAPILogResourceFilter>();

            #region 压缩
            services.AddResponseCompression();  //注册压缩服务
            #endregion

            #region NewtonsoftJson

            services.AddControllers().AddNewtonsoftJson(options =>
            {
                //修改属性名称的序列化方式，首字母小写
                options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

                //修改时间的序列化方式
                options.SerializerSettings.Converters.Add(new IsoDateTimeConverter() { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" });
                options.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
            });
            #endregion

            #region Swagger
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "英泽&智显联合开发人脸机调试器 v1.0", Version = "v1" });
            });
            #endregion

            #region JWT

            #region 读取证书
            string path = Path.Combine(Directory.GetCurrentDirectory(), "client-rsa.pfx");
            string key = File.ReadAllText(path);
            X509Certificate2 x509 = new X509Certificate2(path, "YunPC61006535");

            var publicRSA = x509.PublicKey.GetRSAPublicKey();
            var rsaKey = new RsaSecurityKey(publicRSA);
            #endregion

            #region JWT Server RS256
            JWTTokenOptions.X509 = x509;
            services.AddScoped<IJWTService, JWTRSService>();
            services.Configure<JWTTokenOptions>(this.Configuration.GetSection("JWTTokenOptions"));
            #endregion


            #region JWT校验  RS

            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuer = true,//是否验证Issuer
                    ValidateAudience = true,//是否验证Audience
                    ValidateLifetime = true,//是否验证失效时间
                    ValidateIssuerSigningKey = true,//是否验证SecurityKey
                    ValidAudience = this.Configuration["Audience"],//Audience
                    ValidIssuer = this.Configuration["Issuer"],//Issuer，这两项和前面签发jwt的设置一致
                    IssuerSigningKey = rsaKey,
                    //IssuerSigningKeyValidator = (m, n, z) =>
                    // {
                    //     Console.WriteLine("This is IssuerValidator");
                    //     return true;
                    // },
                    //IssuerValidator = (m, n, z) =>
                    // {
                    //     Console.WriteLine("This is IssuerValidator");
                    //     return "http://localhost:3698";
                    // },
                    //AudienceValidator = (m, n, z) =>
                    //{
                    //    Console.WriteLine("This is AudienceValidator");
                    //    return true;
                    //    //return m != null && m.FirstOrDefault().Equals(this.Configuration["Audience"]);
                    //},//自定义校验规则，可以新登录后将之前的无效
                };
                options.Events = new JwtBearerEvents();
                options.Events.OnChallenge += jwt_OnChallenge;
            });

            #endregion
            #endregion
            // services.AddMyBackgroundService(Configuration);
            //   WebSocketServerChannel.ParsResult();
            services.AddMyBackgroundService(Configuration);
        }

        private async Task jwt_OnChallenge(JwtBearerChallengeContext arg)
        {
            arg.HandleResponse();
            _ilogger.LogInformation($" {arg.Request.Path} JWT 验证失败");


            var result = new JsonResultModel(401, $"Unauthorized,{arg.Error},{arg.ErrorDescription}");
            var rst = arg.Response;
            rst.StatusCode = StatusCodes.Status200OK;
            rst.ContentType = "application/json; charset=utf-8";
            await rst.WriteAsync(result.ToJson());
        }



        public void ConfigureContainer(ContainerBuilder containerBuilder)
        {
            containerBuilder.RegisterModule<CustomAutofacModule>();

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory factory, IServiceProvider provider)
        {
            _ilogger = factory.CreateLogger<Startup>();
            _ilogger.LogInformation($"FC8280T 服务器已启动");
            //_ilogger.LogInformation($"服务器根目录：{Directory.GetCurrentDirectory()}");

            //app.ApplicationServices.GetService<Startup>();

            #region 配置Reids
            //_ilogger.LogInformation($"开始配置Redis 服务");
            //RedisConfigInfo.WriteServerList = Configuration["RedisOptions:WriteServerList"];
            //RedisConfigInfo.ReadServerList = Configuration["RedisOptions:ReadServerList"];
            //RedisConfigInfo.DefaultDb = int.Parse(Configuration["RedisOptions:DefaultDb"]);
            //RedisConfigInfo.MaxConnectFailCount = 0;
            ////测试Redis连接
            //try
            //{
            //    using (var redis = new RedisStringService())
            //    {
            //        redis.Set("Test:FC8280TServer", 1);
            //        redis.Incr("Test:FC8280TServer");
            //        redis.IncrBy("Test:FC8280TServer", 10);
            //    }
            //    RedisConfigInfo.MaxConnectFailCount = 2;
            //}
            //catch (System.Exception exredis)
            //{

            //    throw new Exception("Redis 服务测试失败！", exredis);
            //}
            //_ilogger.LogInformation($"Redis 服务测试完毕");
            #endregion

            #region "初始化缓存--缓存预热"
            //_ilogger.LogInformation($"开始初始化缓存");
            //using (var iDBCache = provider.GetService<ICacheService>())
            //{
            //    iDBCache.LoadCache();
            //}
            //_ilogger.LogInformation($"缓存预热完毕");
            #endregion


            var webSocketOptions = new WebSocketOptions()
            {
                KeepAliveInterval = TimeSpan.FromSeconds(10),
            };

            app.UseWebSockets(webSocketOptions);

            #region 压缩
            app.UseResponseCompression();
            #endregion


            #region Swagger
            //app.UseSwagger();
            //app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "FC8280T人脸机调试器 v1.0"));
            #endregion

            #region 接口日志记录

            app.Use(next =>//接口日志记录
            {
                return new RequestDelegate(async context =>
                {
                    var req = context.Request;
                    //if (req.Path.Value.StartsWith("/softpkg"))
                    //{
                    //    Dictionary<string, string> headers = new Dictionary<string, string>();
                    //    HashSet<string> Headerfilter = new HashSet<string>();
                    //    Headerfilter.Add("Cache-Control");
                    //    Headerfilter.Add("Connection");
                    //    Headerfilter.Add("Pragma");
                    //    Headerfilter.Add("Accept");
                    //    Headerfilter.Add("Accept-Language");
                    //    Headerfilter.Add("User-Agent");
                    //    Headerfilter.Add("Host");
                    //    foreach (var item in req.Headers.Keys)
                    //    {
                    //        if (!Headerfilter.Contains(item))
                    //            headers.Add(item, req.Headers[item].ToString());
                    //    }



                    //}
                  //  _ilogger.LogInformation($"{req.Method} URL:{req.Path}  ");
                    await next.Invoke(context);
                });
            });
            #endregion

            DefaultFilesOptions options = new DefaultFilesOptions();
            options.DefaultFileNames.Clear();
            options.DefaultFileNames.Add("index.html");
            app.UseDefaultFiles(options);
            //var staticOption = new StaticFileOptions();
            //var contentTypeProvider = new FileExtensionContentTypeProvider();
            //contentTypeProvider.Mappings.Add(".pkg", "application/octet-stream");
            //staticOption.ContentTypeProvider = contentTypeProvider;
            app.UseStaticFiles();
            //app.UseStaticFiles(new StaticFileOptions() { 
            //    FileProvider = new PhysicalFileProvider(Directory.GetCurrentDirectory()),
            //    RequestPath=new PathString("/wwwroot")
            //});


            app.UseMiddleware<ExceptionMiddleware>();
            app.UseMiddleware<FaceAPISoftwareDownloadLogMiddleware>();
            app.UseMiddleware<FaceAPILogResourceMiddleware>();



            app.UseRouting();

            #region  JWT
            app.UseAuthentication();//鉴权：解析信息--就是读取token，解密token
            app.UseAuthorization();
            app.UseUserRegister();
            #endregion


            #region  使用Websocket
            //使用Websocket
            //app.UseWebSockets();
            //app.UseMiddleware<ChatWebSocketMiddleware>();
            //app.UseMiddleware<EchoWebSocketMiddleware>();
            #endregion



            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });


            #region 网站默认页
            //DefaultFilesOptions options = new DefaultFilesOptions();
            //options.DefaultFileNames.Add("index.html");    //将index.html改为需要默认起始页的文件名.
            //app.UseDefaultFiles(options);

            //app.Run(ctx =>
            //{
            //    if(ctx.Request.Path.Value)
            //    ctx.Response.Redirect("/index.html"); //可以支持虚拟路径或者index.html这类起始页.
            //    return Task.FromResult(0);
            //});

            #endregion



        }
    }
}
